/********************************************************************************************************
 * @file BeaconRecordService.java
 *
 * @brief for TLSR chips
 *
 * @author telink
 * @date Sep. 30, 2019
 *
 * @par Copyright (c) 2019, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *******************************************************************************************************/
package com.telink.lt.ui;

import android.bluetooth.BluetoothDevice;

import com.telink.lt.AdvertisingDevice;
import com.telink.lt.TelinkLog;
import com.telink.ota.util.Arrays;

import java.util.ArrayList;
import java.util.List;

public class BeaconRecordService {
    private List<AdvertisingDevice> allRecords;

    private List<AdvertisingDevice> displayRecords;

    private RecordFilter filter = new RecordFilter();

    private RecordChangeListener listener;

    private long lastUpdateTime = 0;

    private static final long UPDATE_SPACE = 1000;

    private static final BeaconRecordService instance = new BeaconRecordService();

    public static BeaconRecordService getInstance() {
        return instance;
    }

    public void init(RecordChangeListener listener) {
        this.allRecords = new ArrayList<>();
        this.displayRecords = new ArrayList<>();
        this.listener = listener;
    }

    public void clearData() {
        allRecords.clear();
        this.displayRecords.clear();
        lastUpdateTime = 0;
        refresh();
    }

    public List<AdvertisingDevice> getDisplayRecords() {
        return displayRecords;
    }

    public boolean syncFilter(RecordFilter filter) {
        if (this.filter.equals(filter)) return false;
        this.filter.rssi = filter.rssi;
        this.filter.nameOrAddress = filter.nameOrAddress;
        return true;
    }

    public List<AdvertisingDevice> updateFilter(RecordFilter filter) {
        if (!syncFilter(filter)) {
            return displayRecords;
        }
        displayRecords.clear();
        boolean filterPass;
        for (AdvertisingDevice device : allRecords) {
            filterPass = filterDevice(device);
            if (filterPass) {
                int position = displayRecords.indexOf(device);
                if (position == -1) {
                    displayRecords.add(device);
                } else {
                    displayRecords.set(position, device);
                }
            }
        }
        refresh();
        return displayRecords;
    }

    private boolean filterDevice(AdvertisingDevice device) {
        if (device.rssi < filter.rssi) {
            return false;
        }
        String name = device.device.getName();
        boolean strPair = device.device.getAddress().contains(filter.nameOrAddress.toUpperCase())
                || (name != null && name.toUpperCase().contains(filter.nameOrAddress.toUpperCase()));
        if (!strPair) return false;
        return true;
    }

    public List<AdvertisingDevice> findRecords(BluetoothDevice bluetoothDevice) {
        List<AdvertisingDevice> rec = new ArrayList<>();
        outer:
        for (AdvertisingDevice advertisingDevice : allRecords) {
            if (advertisingDevice.device.equals(bluetoothDevice)) {
                for (AdvertisingDevice inner : rec) {
                    if (Arrays.equals(inner.scanRecord, advertisingDevice.scanRecord)) {
                        continue outer;
                    }
                }
                rec.add(advertisingDevice);
            }
        }
        return rec;
    }


    public void pushRecord(AdvertisingDevice device) {
        allRecords.add(device);
        boolean filterPass = filterDevice(device);
//        TelinkLog.d("push record: " + filterPass);
        if (!filterPass) return;
        int position = displayRecords.indexOf(device);
        if (position == -1) {
            displayRecords.add(device);
            insertItem(device, displayRecords.size() - 1);
        } else {
            AdvertisingDevice inner = displayRecords.get(position);
            if (inner.rssi != device.rssi || !Arrays.equals(inner.scanRecord, device.scanRecord)) {
                displayRecords.set(position, device);
                final long curTIme = System.currentTimeMillis();
                final long during = curTIme - lastUpdateTime;
                TelinkLog.d("record: set during: " + during + " position: " + position);

                if (lastUpdateTime == 0 || (during > UPDATE_SPACE)) {
                    lastUpdateTime = curTIme;
//                    updateItem(device, position);
                    refresh();
                }
            }
        }
    }

    public void refresh() {
        if (listener != null) {
            TelinkLog.d("list count: " + displayRecords.size());
            listener.onRefresh();
        }
    }

    public void updateItem(AdvertisingDevice device, int position) {
        if (listener != null) {
            listener.onRecordUpdate(device, position);
        }
    }

    public void insertItem(AdvertisingDevice device, int position) {
        if (listener != null) {
            listener.onRecordInsert(device, position);
        }
    }

    interface RecordChangeListener {
        void onRecordInsert(AdvertisingDevice advertisingDevice, int position);

        void onRecordUpdate(AdvertisingDevice device, int position);

        void onRefresh();
    }
}
